package vethbr

import (
	"bytes"
	"fmt"
	"log"
	"net"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

// setupIPTablesSNAT 设置 iptables 对应 bridge MASQUERADE 规则
// 类似于： iptables -t nat -A POSTROUTING -s 172.20.0.0/24 ! -o br0 -j MASQUERADE
// + iptables -t nat：表示操作的是iptables的nat表。iptables有多个表，如filter（用于过滤数据包）、nat（网络地址转换）、mangle （修改数据包内容）等，这里明确要在nat表中设置规则。
// + -A POSTROUTING：-A是追加（Append）的意思，也就是在POSTROUTING链末尾添加一条新规则。POSTROUTING链位于 NAT 表中，这个链里的规则会在数据包即将离开本机、前往其他网络设备时被处理，是做源地址转换（SNAT）的关键位置。
// + -s 172.20.0.0/24：指定源地址范围，只有来自172.20.0.0/24这个网段的数据包才会匹配这条规则。这确保了规则仅作用于特定子网内产生的流量。
// + ! -o br0：!表示取反，-o 用来匹配数据包的输出接口，这条语句意思是数据包的输出接口不是br0。即源自172.20.0.0/24网段且不通过br0接口往外发送的数据包，才会进入后续的处理流程。
// + -j MASQUERADE：-j 是跳转（jump）的缩写，这里指定动作是MASQUERADE。MASQUERADE是一种动态的源地址伪装技术，它会自动使用当前系统可用的公网 IP 地址，把数据包的源 IP 地址替换掉，从而隐藏内部网络的真实 IP，让外部网络以为数据包是从当前主机的公网 IP 发出的，常用于实现局域网主机共享单个公网 IP 上网。
func setupIPTablesSNAT(bridgeName string, subnet *net.IPNet) error {
	// 拼接命令
	iptablesCmd := fmt.Sprintf("-t nat -A POSTROUTING -s %s ! -o %s -j MASQUERADE", subnet.String(), bridgeName)
	cmd := exec.Command("iptables", strings.Split(iptablesCmd, " ")...)
	// 执行该命令
	output, err := cmd.Output()
	if err != nil {
		log.Printf("[vethbr]iptables setup SNAT Output, %v\n", output)
		return err
	}

	return nil
}

func DeleteIPTableSNAT(bridgeName string, subnet *net.IPNet) error {
	// 拼接命令 - 把上边的 -A 改为 -D 即可
	iptablesCmd := fmt.Sprintf("-t nat -D POSTROUTING -s %s ! -o %s -j MASQUERADE", subnet.String(), bridgeName)
	cmd := exec.Command("iptables", strings.Split(iptablesCmd, " ")...)
	// 执行该命令
	output, err := cmd.Output()
	if err != nil {
		log.Printf("[vethbr]iptables delete SNAT Output, %v\n", output)
		return err
	}

	return nil
}

// setupIPTablesDNAT 设置 iptables对应bridge的 PREROUTING 链和 OUTPUT 链
// PREROUTING链将外部请求对宿主机的80端口请求转到容器内
// iptables -t nat -A PREROUTING  ! -i br0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.20.0.10:80
// OUTPUT链将当前宿主机上对80的请求转到容器内
// iptables -t nat -A OUTPUT               -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.20.0.10:80
func SetupIPTablesDNAT(bridgeName string, hostPort int16, containerIP net.IP, containerPort int16) error {
	// PREROUTING 的新增
	err := handleIptablesDNATChainPrerouting("A", bridgeName, hostPort, containerIP, containerPort)
	if err != nil {
		return err
	}
	err = handleIptablesDNATChainOutput("A", hostPort, containerIP, containerPort)
	if err != nil {
		return err
	}
	return nil
}

func DeleteIPTablesDNATPrerouting(bridgeName string, hostPort int16, containerIP net.IP, containerPort int16) error {
	return handleIptablesDNATChainPrerouting("D", bridgeName, hostPort, containerIP, containerPort)
}

func DeleteIPTablesDNATOutput(hostPort int16, containerIP net.IP, containerPort int16) error {
	return handleIptablesDNATChainOutput("D", hostPort, containerIP, containerPort)
}

// 处理DNAT的PREROUTING链
// @param string action 枚举值 A 或者 D，即添加或者删除
func handleIptablesDNATChainPrerouting(action string, bridgeName string, hostPort int16, containerIP net.IP, containerPort int16) error {
	// 拼接命令
	preRoutingCommand := fmt.Sprintf("-t nat -%s PREROUTING ! -i %s -p tcp -m tcp --dport %d -j DNAT --to-destination %s:%d", action, bridgeName, hostPort, containerIP.String(), containerPort)
	preRoutingCmd := exec.Command("iptables", strings.Split(preRoutingCommand, " ")...)
	// 执行该命令
	preRoutingResult, err := preRoutingCmd.Output()
	if err != nil {
		log.Printf("[vethbr]iptables setup/delete DNAT Output: %v; command:%s; err: %v\n", preRoutingResult, preRoutingCommand, err)
		return err
	}
	log.Printf("[vethbr]iptables PREROUTING command:%s;", preRoutingCommand)
	return nil
}

// 处理DNAT的OUTPUT链
// @param string action 枚举值 A 或者 D，即添加或者删除
func handleIptablesDNATChainOutput(action string, hostPort int16, containerIP net.IP, containerPort int16) error {
	// 拼接命令
	outputCommand := fmt.Sprintf("-t nat -%s OUTPUT -p tcp -m tcp --dport %d -j DNAT --to-destination %s:%d", action, hostPort, containerIP.String(), containerPort)
	outputCmd := exec.Command("iptables", strings.Split(outputCommand, " ")...)
	// 执行该命令
	outputResult, err := outputCmd.Output()
	if err != nil {
		log.Printf("[vethbr]iptables setup/delete OUTPUT Output, %v; command:%s; err: %v\n", outputResult, outputCommand, err)
		return err
	}
	log.Printf("[vethbr]iptables OUTPUT command:%s;", outputCommand)
	return nil
}

func RunDelete() {
	hostPort := "9999"
	containerIP := "192.168.88.27"
	containerPort := "80"

	err := deletePreRouting(hostPort, containerIP, containerPort)
	if err != nil {
		fmt.Printf("Error deleting DNAT rule: %v\n", err)
	}
}

func deletePreRouting(hostPort, containerIP, containerPort string) error {
	return deleteDNATRuleByNo("PREROUTING", hostPort, containerIP, containerPort)
}

func deleteOutput(hostPort, containerIP, containerPort string) error {
	return deleteDNATRuleByNo("OUTPUT", hostPort, containerIP, containerPort)
}

// deleteDNATRule 删除指定的 DNAT 规则,使用序号的方式
func deleteDNATRuleByNo(link, hostPort, containerIP, containerPort string) error {
	// 获取包含行号的规则列表
	//cmd := exec.Command("iptables", "-t", "nat", "-L", "PREROUTING", "-n", "--line-numbers")
	//cmd := exec.Command("iptables", "-t", "nat", "-L", "OUTPUT", "-n", "--line-numbers")
	cmd := exec.Command("iptables", "-t", "nat", "-L", link, "-n", "--line-numbers")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("failed to list iptables rules: %v", err)
	}

	// 定义一个正则表达式模式来匹配特定的 DNAT 规则
	pattern := fmt.Sprintf(`(\d+)\s+%s\s+(.*)\s+tcp dpt:%s to:%s:%s\s+`, link, hostPort, containerIP, containerPort)
	log.Println(pattern)
	re := regexp.MustCompile(pattern)
	/*
		num  target     prot opt source               destination
		1    DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
		2    DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:192.168.88.17:80
		3    DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8888 to:192.168.88.18:80
		4    DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8899 to:192.168.88.25:80
		5    DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8989 to:192.168.88.26:80
		6    DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:9999 to:192.168.88.27:80
	*/
	log.Println(out.String())

	// 查找匹配的规则行号
	matches := re.FindStringSubmatch(out.String())
	if len(matches) == 0 {
		return fmt.Errorf("DNAT rule not found")
	}

	lineNumber, err := strconv.Atoi(matches[1])
	if err != nil {
		return fmt.Errorf("failed to parse line number: %v", err)
	}

	// 删除指定行号的规则
	deleteCmd := exec.Command("iptables", "-t", "nat", "-D", "PREROUTING", strconv.Itoa(lineNumber))
	err = deleteCmd.Run()
	if err != nil {
		return fmt.Errorf("failed to delete DNAT rule: %v", err)
	}

	log.Printf("Successfully deleted DNAT rule for host port %s -> container %s:%s\n", hostPort, containerIP, containerPort)
	return nil
}
